home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Languguage OS 2
/
Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO
/
language
/
embedded
/
mcu
/
b5_boot.arc
/
EPB5.C
next >
Wrap
Text File
|
1989-03-22
|
27KB
|
882 lines
/**************************************************
* EPB5 - MC68HC705B5 Serial loader *
* *
* Compiled using Microsoft C 5.0 Compiler *
* as follows: *
* qcl epb5.c /F *
* link epb5 /ST:0x4fff *
* *
* Original code by O. Pilloud *
* Rewritten by H. Tireford - March 1989 *
* *
**************************************************
*/
# define IGNORE_CKSUM /* comment out if checksum errors are to be flagged */
# include <c:\c\bios.h>
# include <c:\c\stdio.h>
# include <c:\c\stdlib.h>
# include <c:\c\string.h>
# include <c:\c\ctype.h>
# include <c:\c\conio.h>
# include <c:\c\setjmp.h>
/* MCU dependencies
*/
# define ARRAYSZ 8192 /* B5 memory size (max) */
# define MAXREC (ARRAYSZ+100) /* max size of echo buffer */
# define FUSE_ADDR 0x1efe
# define SECE 0x80
# define BEG_ADDR 0x100
# define END_ADDR 0x200
# define TOP_ADDR 8192
# define BOT_ADDR 256
# define REVISION "B.0"
# define BFSIZE 128 /* max record length */
# define COM1 0 /* serial port number */
# define FALSE 0
# define TRUE !FALSE
# define uchar unsigned char
# define FILE_END 0
# define REC_OK 1 /* valid S0 or S1 record */
# define E_COUNT -1 /* invalid character count */
# define E_BCOUNT -2 /* invalid byte count */
# define E_ADDR -3 /* invalid address field */
# define E_CHAR -4 /* char in S-rec data field is not hex */
# define E_CKSUM -5 /* invalid checksum */
# define E_SEG -6 /* too many segments */
# define BFSIZE 128 /* length of buffer to hold S records */
# define MAX_SEG 50 /* maximum number of segments in file */
unsigned int
line, /* input file record number */
addr,
beg_add,
end_add,
echo_cnt,
loaded,
dumped,
seg_num;
uchar
buf [BFSIZE], /* input buffer */
pgm [80], /* downloadable file name */
array [ARRAYSZ], /* S19 file array */
* echo_ptr,
echo [MAXREC],
rx [4], /* 4-byte received data */
word [4], /* 4-byte transmit data */
comstat, /* bios serial function result */
last_recv, /* last byte received from MCU */
sync; /* communication sync flag */
uchar dummy_rec [4] = {0x00, 0x00, 0x00, 0x00}; /* record of zeroes */
uchar exec_rec [4] = {0x20, 0xfe, 0x00, 0x00}; /* BRA * */
int NEG = 0x8237; /* negative address to trigger RAM exec */
int XADR = 0x0094;
int PROG = 0x0250;
jmp_buf mark;
struct segment {
unsigned
addr,
count;
} segment [MAX_SEG];
struct rec {
unsigned int addr; /* load address */
char * ptr; /* pointer to next hex pair in data field */
unsigned char
type, /* record type (ascii 0 or 1) */
bcount; /* number of data bytes (or hex pair) */
/* pointed to by "ptr" */
} rec;
char * serial_error[] = {
"Data ready",
"Overrun",
"Parity",
"Framing",
"Break",
"Tx Hold empty",
"Tx shift empty",
"Timeout",
};
char * load_error [] = {
"invalid character count", /* E_COUNT */
"invalid byte count", /* B_COUNT */
"invalid address field", /* E_ADDR */
"non hexadecimal character", /* E_CHAR */
"invalid checksum", /* E_CKSUM */
"too many segments", /* E_SEG */
};
/* Convert lower-case to upper-case
*/
char
upper (char c)
{
if (c >= 'a' && c <= 'z')
c = c - 'a' + 'A';
return (char) c;
}
/* Return binary value of an hex character PLUS 1,
* or return 0 if not an hex char.
*/
unsigned
ishex (char c)
{
c = upper (c);
if (isdigit (c))
return c - '0' + 1;
if (c < 'A' || c > 'F')
return 0;
return c - 'A' + 11;
}
/* Initialize PC serial port
*/
void
init_ser (int port)
{
comstat = (uchar) _bios_serialcom(_COM_INIT,
port,
_COM_CHR8 |
_COM_NOPARITY |
_COM_9600 );
}
/* Output character to serial port
*/
void
send_char (uchar c, int port)
{
comstat = (uchar) _bios_serialcom (_COM_SEND, port, c);
}
/* Buffer character echoed by MCU
*/
void
save_echo (uchar c)
{
if (echo_cnt ++ < MAXREC)
* echo_ptr ++ = c;
else
printf ("echo buffer overflow\n");
}
/* Dump echo buffer to console
*/
void
dump_echo (void)
{
uchar * p, * q, c;
int i, j, cnt;
p = & echo[7];
if (echo_cnt < 7) {
printf ("echo buffer is empty\n");
return;
}
printf ("\n*** Bytes received from MC68HC705B5 MCU ***\n");
for (i=0; p < echo_ptr; i++) {
if ( (i % 16) == 0) {
q = p;
cnt = 0;
printf ("\n%.4x ", i);
}
/* for each byte, display its value in ascii hex
*/
printf ("%.2x ", (unsigned int) * p ++);
cnt ++;
/* display ascii printable equivalent
* characters at end of line (group of 16 bytes).
*/
if ((i & 15) == 15) {
printf (" ");
for (j=0; j < cnt; j++) {
c = * q++;
if (! (c >= ' ' && c <= '~'))
c = '.';
printf ("%c", c);
}
if (user_abort()) /* check for abort */
break;
}
}
printf ("\n");
}
/* Compare bytes we sent with bytes echoed by MCU
*/
void
verify (void)
{
uchar * p, c;
int i, j, k, flag, err, u_abort;
if (! dumped) {
printf ("Nothing downloaded yet\n");
return;
}
err = flag = u_abort = 0;
p = & echo[7];
k = echo_cnt - 7;
/* the bytes we sent to MCU were fetched from array
* using the definitions of file segments which was
* constructed at the time the file was loaded in PC.
*/
for (i = 1; i < seg_num && ! u_abort; i++) {
addr = segment [i] . addr;
j = segment [i] . count;
if (k < j) {
printf ("Host sent %d bytes (segment %.4x).\n", j, addr);
printf ("MCU did not echo %s.\n", k > 0 ? "all of them" : "any");
err ++;
}
while (j --) {
if ( (c = array [addr]) != * p ) {
err ++;
if ((flag % 16) == 0) {
if (user_abort()) {
u_abort ++;
break;
}
printf ("\nAddr Sent Recv\n");
}
printf ("%.4x: %.2x %.2x %c",
addr, c, * p, (flag++ & 3) == 3 ? '\n' : ' ');
}
addr ++;
p ++;
k --;
}
if (k < 0)
break;
}
printf ("\nVerify %s\n", err ? "failed" : "succeeded");
}
void
reset_mcu (int mark)
{
printf ("Reset MCU %c\n", mark == TRUE ? '!' : ' ');
}
int
user_abort (void)
{
unsigned c;
if (_bios_keybrd (_KEYBRD_READY) ) {
c = _bios_keybrd (_KEYBRD_READ) & 255;
c = upper ((uchar) c);
if (c=='X' || c=='Q' || c == 0x3)
return 1;
}
return 0;
}
/* Wait until 4 consecutive valid bytes are received
* from MCU (as a result of MCU reset).
*/
void
synchronize (void)
{
unsigned c, d, cnt, err;
reset_mcu (FALSE);
for (err = sync = cnt = 0; cnt < 1; ) {
if (user_abort())
longjmp (mark, -1);
c = _bios_serialcom (_COM_RECEIVE, COM1, 0);
d = (c >> 8) & 255;
last_recv = (uchar) c & 255;
if (! d) {
err = 0;
cnt ++;
}
else {
cnt = 0;
if ( ++ err % 8 == 0)
reset_mcu (TRUE);
}
}
sync ++;
}
/* Get character from serial port; wait
* until one is received, if necessary.
*/
uchar
rec_char (int port)
{
unsigned c, i, j, d, cnt;
/* Allow for a maximum of 16 errors prior to aborting
*/
for (cnt = 0; cnt < 16; cnt ++) {
if (user_abort())
break;
c = _bios_serialcom (_COM_RECEIVE, port, 0);
d = (c >> 8) & 255;
if (! d) { /* valid character. return it */
cnt = 0;
c &= 255;
save_echo (last_recv = (uchar) c);
return (uchar) (c);
}
/* Display relevant error message.
*/
for (i=1, j=0; j < 8; i <<= 1, j++)
if (i & d)
printf (" -%s- ", serial_error[j]);
printf ("(%.4x)\n", c);
}
/* Abort, i.e., re-enter command interpreter due to
* too many communication errors or operator's abort.
*/
printf ("\n%s !!!\n",
cnt == 16 ? "serial link problem" : "aborted");
longjmp (mark, -1);
}
/* Send 6 bytes to MCU (target address + 4 data bytes)
* while simultaneously accepting 4 bytes from it.
*/
void
protocol (uchar word[], uchar rx[], int address)
{
int i;
uchar * wp, * rp;
wp = & word[0];
rp = & rx[0];
/* Receive one byte from MCU before sending data unless
* at the very beginning of the transfer.
*/
if (sync != 1)
* rp++ = rec_char (COM1); /* receive first (lo) echo */
else {
* rp ++ = last_recv;
sync ++;
}
send_char ((uchar) (address >> 8), COM1); /* send address hi */
* rp++ = rec_char (COM1); /* receive second echo */
send_char ((uchar) (address & 0xff), COM1); /* send address lo */
* rp++ = rec_char (COM1); /* receive third echo */
send_char (* wp++, COM1); /* send first (lo) data byte */
* rp = rec_char (COM1); /* receive fourth echo */
send_char (* wp++, COM1); /* send second data byte */
send_char (* wp++, COM1); /* send third data byte */
send_char (* wp, COM1); /* send fourth data byte */
}
/* Download array, 4 bytes at a time, accounting for
* the file segments constructed by "loadfile".
*/
void
main_proc (void)
{
int i, j, k;
unsigned int
addr;
for (i = 1; i < seg_num; i++) {
addr = segment [i] . addr;
j = segment [i] . count;
do {
for (k=0; k < 4; k++)
word [k] = array [addr + k];
protocol (word, rx, addr);
addr += 4;
j -= 4;
} while (j > 0);
}
}
/* send 3 records to empty the pipeline, blow the fuse
* if required and be ready for the next device
*/
void
reset_pipe (void)
{
protocol (exec_rec, rx, XADR);
protocol (dummy_rec,rx, PROG);
protocol (dummy_rec,rx, NEG );
}
/* Display menu of commands and return user's selection
*/
int
prompt (void)
{
int c;
printf ("\n\n\t* S \tShow MCU memory contents");
printf ("\n\t* F \tLoad S19 file from disk");
printf ("\n\t* D \tDownload last loaded file to MCU");
printf ("\n\t* E \tExamine \'echo\' buffer");
printf ("\n\t* V \tVerify \'echo\' buffer against downloaded file");
printf ("\n\t* X \tExit\n");
while (TRUE) {
printf ("\n\t Your choice ? ");
c = getche();
c = upper ((uchar) c);
if (c == 'X')
c = 'Q';
if (c == 'S' || c == 'D' || c == 'Q' || c == 'F' || c == 'E' || c == 'V') {
putchar ('\n');
break;
}
}
return c;
}
/* Initialize MCU memory image in PC
*/
void
clear_array (void)
{
int i;
uchar * p;
for (i = 0, p = array; i < ARRAYSZ; i++)
* p ++ = 0;
}
/* Get beginning and ending addresses for MCU memory display
*/
void
get_limits (void)
{
char inp [40];
unsigned int
beg, end;
while (TRUE) {
printf ("Beg addr %.4x ", beg_add);
gets (inp);
if (inp[0])
sscanf (inp, "%x", & beg);
else
beg = beg_add;
printf ("End addr %.4x ", end_add);
gets (inp);
if (inp[0])
sscanf (inp, "%x", & end);
else
end = end_add;
if (beg > end)
continue;
if (beg % 4)
beg &= ~3;
if (end % 4) {
end &= ~3;
end += 4;
}
if ( (beg <= end) && end <= TOP_ADDR && beg >= BOT_ADDR) {
beg_add = beg;
end_add = end;
break;
}
}
}
/* Read "n" hex char pointed to indirectly by "s" and store the converted
* value into location pointed to by "v". Update character pointer.
* Return 0 if valid hex string, non-zero otherwise.
*/
int
gethex (char * * s, unsigned * v, unsigned n)
{
char * p;
unsigned i, x;
i = 0;
p = * s;
while (n --) {
if (! (x = ishex (* p++)) )
break;
i <<= 4;
i |= (x - 1);
}
* v = i;
* s = p;
return x == 0;
}
/* Get next S0 or S1 record from input file.
* return 0 if EOF, <0 if invalid record, >0 otherwise.
*/
int
get_S_record (FILE * fp)
{
char c, * s, * p;
unsigned char ck;
unsigned val, len;
while (fgets (buf, BFSIZE-1, fp) != (char *) NULL ) {
line ++;
for (s = buf; * s; s++)
* s = upper (* s);
if (* -- s != '\n') /* line length exceeds buf capacity */
continue; /* discard */
len = s - buf; /* record length, incl. S-rec type */
s = buf;
if (* s ++ != 'S') /* not an S record. ignore. */
continue;
c = * s++;
switch (c) {
case '9':
break;
case '0':
case '1':
rec . type = c;
if ( len < 4 || gethex (&s, &val, 2))
return E_COUNT;
ck = val; /* start building checksum */
if ( len != (((rec . bcount = val) <<1) + 4) )
return E_BCOUNT;
if ( len < 8 || gethex (&s, &val, 4))
return E_ADDR;
ck += val & 255;
ck += (val >> 8) & 255;
rec . addr = val;
rec . bcount -= 3; /* number of data bytes (cksum excl.) */
rec . ptr = s; /* pointer to first data byte in record */
len = rec . bcount;
/* continue to compute checksum on data bytes and
* check that it matches the one at end of record
*/
while (len --) {
if (gethex (&s, &val, 2))
return E_CHAR;
ck += val & 255;
}
ck = ~ck; /* one's complement */
gethex (&s, &val, 2);
if (ck != val & 255) {
# ifdef IGNORE_CKSUM
printf ("%s*** %s (error ignored) at line %d\n",
buf, load_error [-E_CKSUM - 1], line);
return REC_OK;
# endif
return E_CKSUM;
}
/* record passed all tests. exit
* and tell the world it is valid.
*/
return REC_OK;
default: /* ignore records other than S0 or S1 */
break;
}
continue;
}
return FILE_END; /* EOF */
}
/* Load file given as argument; if it does not exist, try
* to load same file with extension ".S19", if any.
*/
void
loadfile (char * s)
{
FILE * infil;
int i, j, x;
unsigned int
val, k;
char * p;
loaded = 0;
strcpy (pgm, s);
while (TRUE) {
if ( (infil = fopen (pgm, "r")) != (FILE *) NULL)
break;
strcat (pgm, ".s19");
if ( (infil = fopen (pgm, "r")) == (FILE *) NULL) {
printf ("Cannot open file %s\n", s);
return;
}
break;
}
printf ("Loading file %s ...\n", pgm);
clear_array ();
line = seg_num = 0;
segment [0] . addr = 0xffff;
segment [0] . count = 0;
/* Construct file segments while loading
*/
while ( (i = get_S_record (infil)) > 0 ) {
j = rec . bcount;
p = rec . ptr;
if ( rec . type == '0') { /* S0 record handling */
if (! j)
printf ("(no header)\n");
else {
printf ("header: ");
while (j --) {
gethex (&p, &val, 2);
putchar ( (uchar) val & 255 );
}
putchar ('\n');
}
continue;
}
/* S1 record handling */
if ( rec . addr == (segment [seg_num] . addr + segment [seg_num] . count) )
segment [seg_num] . count += rec . bcount;
else {
if (seg_num ++ >= MAX_SEG) {
i = E_SEG;
break;
}
printf ("getting segment %.4x\n", rec . addr);
segment [seg_num] . addr = rec . addr;
segment [seg_num] . count = rec . bcount;
}
while (j --) {
gethex (&p, &val, 2);
array [rec . addr ++] = (uchar) val & 255;
}
}
seg_num ++;
fclose (infil);
/* adjust segments so that their beg address
* be a multiple of 4.
*/
for (j=1; j < seg_num; j++) {
k = segment [j] . addr;
x = k % 4;
if (x) {
segment [j] . addr &= ~3;
segment [j] . count += x;
}
}
if (i < 0)
printf ("%s\n%s at line %d\n", buf, load_error [-i - 1], line);
else {
loaded ++;
dumped = 0;
i = seg_num -1;
printf ("%d segment%sloaded\n", i, i == 1 ? " " : "s ");
printf ("\nSecurity fuse blowing is%senabled\n",
array [FUSE_ADDR] & SECE ? " " : " not ");
}
}
/* Program entry point
*/
void
main (int argc, char *argv[])
{
char name [80];
int cmd;
printf ("\nEPB5 Serial Loader, rev %s\n", REVISION) ;
/* Set default values
*/
loaded = 0;
beg_add = BEG_ADDR;
end_add = END_ADDR;
/* Load file if one is specified in command line
*/
if (argc == 2)
loadfile (argv [1]);
init_ser (COM1); /* init serial port */
printf ("\nInsert MC68HC705B5 in loader socket.\n");
/*
* Command interpreter
*/
while ( (cmd = prompt()) != 'Q') {
switch (cmd) {
case 'F': /* load file from disk */
printf ("Enter file name: ");
gets (name);
loadfile (name);
break;
case 'E': /* Examine echo buffer */
dump_echo ();
break;
case 'V': /* Verify echo buffer against downloaded file */
if (! loaded)
printf ("No file currently loaded ! (use F command)\n");
else
verify ();
break;
case 'S': /* Show MCU memory contents */
get_limits ();
case 'D': /* Download */
if (cmd == 'D') {
if (! loaded) {
printf ("No file currently loaded ! (use F command)\n");
break;
}
else
printf ("Ready to download %s\n", pgm);
}
echo_cnt = 0;
echo_ptr = & echo[0];
if (! setjmp (mark)) {
synchronize ();
if (cmd == 'D') {
main_proc ();
reset_pipe ();
dumped ++;
verify ();
}
else {
for (addr=beg_add; (addr <= end_add); addr += 4)
protocol (dummy_rec, rx, addr);
reset_pipe ();
dump_echo ();
}
}
break;
default:
break;
}
}
}